/**
 * (c) 2015-2020
 *
 * Author: zeyuphoenix
 *
 * License: www.blogjava.net/zeyuphoenix
 *
 * version: 1.0.0
 */
(function (root, factory) {

    "user strict";

    if (typeof define === 'function' && define.amd) {
        define(['jquery', 'treetable'], factory);
    } else {
        root.TreeTableData = factory($, jQuery.fn.treetable);
    }
}(this, function ($, treetable) {

    "user strict";

    // 提供项目的默认配置项,保持风格统一,覆盖DataTable的配置项
    var defaultOptions = {
        //dom 节点
        databind: null,
        //remote 默认是远程模式
        remote: true,
        //数据请求url地址
        dataurl: '',
        //数据请求参数
        params: {},
        //本地模式才生效
        datas: null,
        /**
         * 表头和表格值的显示主要在这个属性:
         * [{
         *      //不开启可以不写开启覆盖
         *      visible: true,
         *      render: function ( value, row ) {
		 *            return '<a href="'+value+'">Download</a>';
		 *      },
		 *      //默认都是false
		 *      editable: true,
		 *      convert: function (tr, col) {
		 *          return $(tr).find('.salary input').val();
		 *      },
		 *      //显示样式
		 *      class: "",
		 *      width: null, ////"20%" or 20px
		 *      //必须项，表头和对应json的数据
		 *      data: "",
		 *      title: ""
         *  }，
         *  {
         *  }
         * ]
         */
        columns: null,
        /**
         * 因为treetable的一些字段是必须的，并且有强制规定,所以后台返回的数据可能不符合格式,
         * 需要转换
         * 一般id、pid、icon、leaf是必须字段
         * function(datas) {
         *      return paseDatas;
         * }
         */
        parser:null,

        /**是否可展开*/
        expandable: true,
        /**是否可选择*/
        hasSelect: true,
        /**拖拽*/
        hasDrag: true,
        /**载入数据时显示*/
        loadingHTML: '<div class="progress progress-striped active" style="width:50%;margin:auto;"><div class="bar" style="width:100%;"></div></div>',
        /**无数据时显示*/
        noDataFoundHTML: '<b>Sorry, nothing to display.</b>',
        /**初始化完成事件*/
        onInitialized: null,

        //额外接口,必须 和表的option保持一致,不要随便覆盖
        //这个里面的属性会在最后进行覆盖，如果你定义了上面的项目，会进行覆盖
        config: {}
    };

    // 表对象,创建的唯一入口
    var TreeTableData = function (options) {
        this.options = $.extend(true, {}, defaultOptions, options);
        this.__init();
        this.request();
    };

    //表的配置
    //表的对象方法
    TreeTableData.prototype = {

        // 构造
        constructor: TreeTableData,

        // 获取默认的常量

        // 初始化
        __init: function () {
            var self = this;
            // 取得默认配置
            // 表的配置
            this.options.treetableConfig = {};
            this.options.treetableConfig.expandable = this.options.expandable;
            this.options.treetableConfig.onInitialized = this.options.onInitialized;

            //创建表格HTML
            this.$element = $(this.options.databind);
            this.$element.html(this.createTemplate());

            //包含了div,层次改变
            this.$table = this.$element.find('table');
            this.$thead = this.$table.find('thead');

            //head title
            this.$colheader = $('<tr>').appendTo(this.$thead);

            //columns
            this.renderColumns();

            //注册回调事件
        },

        createTemplate: function () {
            //table-striped导致拖拽不变色
            var template = '<table style="clear:both;width:100%;" class="table table-bordered table-hover datatable">' +
                '   <thead></thead>' +
                '   <tbody></tbody>' +
                '</table>';
            return template;
        },

        renderColumns: function () {

            var colHTML = '';

            $.each(this.options.columns, function (index, column) {

                colHTML += '<th data-property="' + column.data + '"';

                if (column.visible == false || column.visible == undefined) {
                    colHTML += ' ';
                } else {
                    colHTML += ' style="display:none;" ';
                }
                var width = column.width;
                if (width && width != '') {
                    colHTML += ' width="' + width + '" ';
                }
                var title = column.title;
                if (title && title != '') {
                    colHTML += '>' + title + '</th>';
                } else {
                    colHTML += '>' + column.data + '</th>';
                }

            });

            this.$colheader.append(colHTML);
        },

        renderCell: function (render, value, row) {
            if (render && typeof render == 'function') {
                return render.call(this, value, row);
            }
            return value;
        },

        /**
         * 发送请求，取得表的数据
         * @params options 重新发送请求传递的参数
         */
        request: function (options) {
            var self = this;

            this.$table.find('tbody').html(this.placeholderRowHTML(this.options.loadingHTML));

            //首先合并更新options
            if (options != null && typeof options == 'object') {
                if (typeof self.options == 'object') {
                    $.extend(true, self.options, options);
                }
            }

            if (this.options.remote == false) {
                self.parseData(self.options);
                return;
            }
            //ajax添加
            var params = $.extend(true, {}, self.options.params);
            //可以自己加入参数，比如分页等
            // console.info(params);

            //发送Ajax请求
            $.ajax({
                url: self.options.dataurl,
                type: 'post',
                //json格式要求严格验证
                dataType: "json",
                data: params,
                success: function (result) {
                    self.options.datas = result;
                    self.parseData(self.options);
                },
                error: function (xhr, error) {
                    console.info('treetable load data error.' + error);
                }
            });
        },

        /**
         * 格式化Ajax请求的数据
         * @param options 所有的配置和数据
         */
        parseData: function (options) {
            var self = this;
            //复制一份结果进行修改，保存原始结果备用
            var datas = $.extend(true, {}, self.options.datas);
            //可以把数据在这里进行转换
            if (self.options.parser != null && $.isFunction(self.options.parser)) {
                datas = self.options.parser.call(this, datas);
            }

            //添加转换好的数据到图
            this.renderData(datas);
        },

        renderData: function (datas) {
            var self = this;

            this.$tbody = this.$table.find('tbody');

            if (typeof datas === 'string') {
                // Error-handling
                self.$tbody.html(self.errorRowHTML(datas));
                //self.stretchHeight();

                self.$element.trigger('loaded');
                return;
            }

            if (datas.length === 0) {
                self.$tbody.html(self.placeholderRowHTML(self.options.noDataFoundHTML));
            } else {

                this.$table.find('tbody').html('');

                $.each(datas, function (index, row) {

                    var $tr = $('<tr/>');
                    $tr.attr('data-tt-id', row['id']);
                    if (row['pid'] != null && row['pid'] != undefined && row['pid'] != 0 && row['pid'] != '0') {
                        $tr.attr('data-tt-parent-id', row['pid']);
                    }
                    $.each(self.options.columns, function (index, column) {
                        var $td = $('<td/>');
                        if (column.class) {
                            $td.addClass(column.class);
                        }
                        $td.html(self.renderCell(column.render, row[column.data], row));

                        if (index == 0) {
                            if (row['icon']) {
                                $td.prepend('<i class="ipad ' + row['icon'] + '"></i>');
                            } else {
                                $td.prepend('<i class="ipad"></i>');
                            }

                            if (row['leaf']) {
                                $td.addClass('leaf');
                            } else {
                                $td.addClass('folder');
                            }
                        }

                        $tr.append($td);
                    });

                    if (index === 0) {
                        self.$tbody.empty();
                    }

                    self.$tbody.append($tr);
                });
            }

            if ($.trim(self.$tbody.html()) === '') {
                self.$tbody.html(self.placeholderRowHTML(self.options.noDataFoundHTML));
            }
            //build treetable
            this.build();
            this.restoreExpanded();
            //self.stretchHeight();
            self.$element.trigger('loaded');
        },

        errorRowHTML: function (content) {
            return '<tr><td style="text-align:center;padding:20px 20px 0 20px;border-bottom:none;" colspan="' +
                this.options.columns.length + '"><div class="alert alert-error">' + content + '</div></td></tr>';
        },

        placeholderRowHTML: function (content) {
            return '<tr><td style="text-align:center;padding:20px;border-bottom:none;" colspan="' +
                this.options.columns.length + '">' + content + '</td></tr>';
        },


        /**
         * 注册表格单击、双击、选择、拖拽的事件
         */
        registerEvent: function () {
            var self = this;
            // Highlight selected row
            if (this.options.hasSelect) {
                this.$table.on("mousedown", "tr", function () {
                    $(".success").not(this).removeClass("success");
                    $(this).toggleClass("success");
                });
            }

            if (this.options.hasDrag) {
                // Drag & Drop Code
                this.$table.find(".leaf, .folder").draggable({
                    helper: "clone",
                    opacity: .75,
                    refreshPositions: true, // Performance?
                    revert: "invalid",
                    revertDuration: 300,
                    scroll: true
                });

                this.$table.find(".leaf, .folder").each(function () {
                    $(this).parents("tr").droppable({
                        accept: ".leaf, .folder",
                        drop: function (e, ui) {
                            var droppedEl = ui.draggable.parents("tr");
                            self.$table.treetable("move", droppedEl.data("ttId"), $(this).data("ttId"));
                        },
                        hoverClass: "accept",
                        over: function (e, ui) {
                            var droppedEl = ui.draggable.parents("tr");
                            if (this != droppedEl[0] && !$(this).is(".expanded")) {
                                self.$table.treetable("expandNode", $(this).data("ttId"));
                            }
                        }
                    });
                });
            }
        },

        /**
         * 初始化后的表格
         *
         * 调用使用treetable("",[""])
         * @return treetable 初始化后的表格
         */
        getTreeTable: function () {
            return this.$table;
        },

        /**
         * 刷新
         */
        refresh: function (params) {
            this.saveExpanded();
            this.request(params);
        },

        /**
         * 获取原始数据
         */
        getTableData: function () {
            return this.options.datas;
        },

        /**
         * Save expanded nodes (TRs) before reloading data table.
         * And after reloading, call restoreExpanded to restore the expand state.
         */
        saveExpanded: function () {

            // save expanded row ids
            var expandedRows = [];
            this.$table.find('tr.expanded').each(function () {
                expandedRows.push($(this).attr('data-tt-id'));
            });
            this.options.expandedRows = expandedRows;
        },

        /**
         * 获取当前展开情况
         * @returns {*}
         */
        getExpanded: function () {
            //first,get expanded
            this.saveExpanded();

            return this.options.expandedRows;
        },

        /**
         * Expand nodes which are saved before reloading data table to restore the expand state.
         */
        restoreExpanded: function () {
            var self = this;
            var expandedRows = this.options.expandedRows || [];
            $.each(expandedRows, function (index, value) {
                //展开指定节点
                try {
                    self.getTreeTable().treetable("expandNode", value);
                } catch(e) {
                    //ignore delete data
                }
            });
        },

        /**
         * 获取拖拽或者修改后的数据
         */
        getData: function () {
            var self = this;
            //树数据
            var tree = this.$table.treetable('tree');

            //表数据
            var trs = this.$table.find('tbody').find('tr');
            var newData = [];
            //查看可编辑列
            var editCol = [];
            $.each(self.options.columns, function (index, column) {
                if (column.editable) {
                    editCol.push(column);
                }
            });
            if (self.options.datas && $.isArray(self.options.datas)) {
                $.each(trs, function (index, tr) {
                    var id = $(tr).attr('data-tt-id');
                    //如果这里表内某项可以编辑，需要取得其上的值
                    for (var i = 0; i < self.options.datas.length; i++) {
                        if (self.options.datas[i]['id'] == id) {
                            //在这里修改值
                            if (editCol.length > 0) {
                                $.each(editCol, function (index, col) {
                                    if (col['convert'] && typeof col['convert'] == 'function') {
                                        self.options.datas[i][col['data']] = col['convert'].call(this, tr, col);
                                    }
                                });
                            }
                            newData.push(self.options.datas[i]);
                            break;
                        }
                    }
                });
            }
            //调整拖拽后的位置
            if (tree && !$.isEmptyObject(tree)) {
                $.each(newData, function (index, data) {
                    var node = tree[data['id']];
                    if (node && node['parentId']) {
                        data['pid'] = node['parentId'];
                    } else {
                        data['pid'] = '0';
                    }
                });
            }

            return newData;
        },

        /**
         * 构造表
         */
        build: function () {

            if (this.options.treetable) {
                this.$table.treetable('destroy');
            }

            //创建treeTable
            this.options.treetable = this.$table.treetable(this.options.treetableConfig);
            //注册事件
            this.registerEvent();
        }
    }

    return TreeTableData;
}))
;
